// SKNotes - a note taking and gathering tool
// Copyright (C) 2009  Stefan Kueng
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;

namespace SKNotes.CustomControls
{
    /// <summary>
    /// An adorner class that contains a TextBox to provide editing capability 
    /// for an EditBox control. The editable TextBox resides in the 
    /// AdornerLayer. When the EditBox is in editing mode, the TextBox is given a size 
    /// it with desired size; otherwise, arrange it with size(0,0,0,0).
    /// </summary>
    internal sealed class EditBoxAdorner : Adorner
    {
        /// <summary>
        /// Initialize the EditBoxAdorner.
        /// </summary>
        public EditBoxAdorner(UIElement adornedElement,
                                UIElement adorningElement)
            : base( adornedElement )
        {
            _textBox = adorningElement as TextBox;
            Debug.Assert( _textBox != null, "No TextBox!" );

            _visualChildren = new VisualCollection( this );


            BuildTextBox( );
        }

        #region Public Methods

        /// <summary>
        /// Specifies whether a TextBox is visible 
        /// when the IsEditing property changes.
        /// </summary>
        /// <param name="isVisible"></param>
        public void UpdateVisibilty(bool isVisible)
        {
            _isVisible = isVisible;
            InvalidateMeasure( );
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Override to measure elements.
        /// </summary>
        protected override Size MeasureOverride(Size constraint)
        {
            _textBox.IsEnabled = _isVisible;
            // if in editing mode, measure the space the adorner element 
            // should cover.
            if ( _isVisible )
            {
                AdornedElement.Measure( constraint );
                _textBox.Measure( constraint );

                // since the adorner is to cover the EditBox, it should return 
                // the AdornedElement.Width, the extra 15 is to make it more 
                // clear.
                return new Size( AdornedElement.DesiredSize.Width + _extraWidth,
                                _textBox.DesiredSize.Height );
            }
            else  // if it is not in editable mode, no need to show anything.
                return new Size( 0, 0 );
        }

        /// <summary>
        /// override function to arrange elements.
        /// </summary>
        protected override Size ArrangeOverride(Size finalSize)
        {
            if ( _isVisible )
            {
                _textBox.Arrange( new Rect( 0, 0, finalSize.Width,
                                                finalSize.Height ) );
            }
            else // if is not is editable mode, no need to show elements.
            {
                _textBox.Arrange( new Rect( 0, 0, 0, 0 ) );
            }
            return finalSize;
        }

        /// <summary>
        /// override property to return information about visual tree.
        /// </summary>
        protected override int VisualChildrenCount
        {
            get { return _visualChildren.Count; }
        }

        /// <summary>
        /// override function to return information about visual tree.
        /// </summary>
        protected override Visual GetVisualChild(int index)
        { return _visualChildren[index]; }

        #endregion

        #region Private Methods

        /// <summary>
        /// Initialize necessary properties and hook necessary events on TextBox, 
        /// then add it into tree.
        /// </summary>
        private void BuildTextBox( )
        {
            _canvas = new Canvas( );
            _canvas.Children.Add( _textBox );
            _visualChildren.Add( _canvas );

            // Bind Text onto AdornedElement.
            Binding binding = new Binding( "Text" );
            binding.Mode = BindingMode.TwoWay;
            binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            binding.Source = this.AdornedElement;

            _textBox.SetBinding( TextBox.TextProperty, binding );

            // when layout finishes.
            _textBox.LayoutUpdated += new EventHandler( OnTextBoxLayoutUpdated );
        }

        /// <summary>
        /// When Layout finish, if in editable mode, update focus status 
        /// on TextBox.
        /// </summary>
        private void OnTextBoxLayoutUpdated(object sender, EventArgs e)
        {
            if ( _isVisible )
                _textBox.Focus( );
        }

        #endregion

        #region Private Variables
        // Visual children
        private VisualCollection _visualChildren;
        // The TextBox that this adorner covers.
        private TextBox _textBox;
        // Whether the EditBox is in editing mode which means the Adorner 
        // is visible.
        private bool _isVisible;
        // Canvas that contains the TextBox that provides the ability for it to 
        // display larger than the current size of the cell so that the entire
        // contents of the cell can be edited
        private Canvas _canvas;

        // Extra padding for the content when it is displayed in the TextBox
        private const double _extraWidth = 15;

        #endregion
    }

}
